/*
    Algoritmo de Cifrado/Descifrado AES
    Copyright (C) 2012 Darío López Padial y César Aguilera 
    @bukosabino
    @Cs4r
    ‏
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

/*******************************************************************************
*
*
*   Ejecución: ./cifrador_en_flujo <semillas.txt> <archivo_a_cifrar>
*
*   Objetivo: Con el generador de secuencias A5/1 a51.py, compone un simulador de 
*       cifrado en ﬂujo que, dada las semillas y el ﬁchero a cifrar, obtiene el
*       cifrado. 
* 
*       Puesto que es un cifrado simetrico, este mismo procedimiento permite el
*       descifrado
*				
*******************************************************************************/
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <boost/lexical_cast.hpp>
#include <bitset>
#include <vector>
#include <string>
using namespace std;

int main(int argc, char **argv) {
    ifstream en_claro, secuencia;
    fstream secuencia_bin;
    ofstream cifrado;
    unsigned int numero_bits;
    
    if(argc != 3){
        cout<<"Número de argumentos inválido"<<endl;
        cout<<"Ejecución: ./cifrador_en_flujo <semillas.txt> <archivo_a_cifrar>"<<endl;
        exit(EXIT_FAILURE);
    }
    
    /* Apertura del archivo a cifrar */
    en_claro.open(argv[2],ios::in | ios::binary);
    
    if(en_claro.is_open()){
        /* Calcular tamanio del archivo en bytes */
        en_claro.seekg(0, ios::end);
        /*  Multiplicar por 8 para obtener el numero de bits */
        numero_bits = static_cast <int> (en_claro.tellg()) * 8;
        
        /* Generar la secuencia cifrante con tantos bits como el tamaño del archivo*/
        string aux = boost::lexical_cast<string>( numero_bits );
        aux = "python a51.py " + string(argv[1]) + " " + aux;
        if(system(aux.c_str()) != 0){
            cout<<"ERROR: Imposible generar secuencia cifrante "<<endl;
            exit(EXIT_FAILURE);
        }
        
        /* Convertir la secuencia de 1's y 0's ASCII a binario */
        string secuencia_ascii_bin;
        secuencia.open("secuencia.txt", ios::in);
	getline(secuencia, secuencia_ascii_bin); // leo la secuencia en 1 string
        secuencia.close();
        
        secuencia_bin.open("secuencia.bin", ios::out | ios::binary);
        for(int i=0;i<numero_bits;i+=8){
            string b = secuencia_ascii_bin.substr(i,8);
            unsigned char byte = 0x00;
            for(int j = 0;j<8;++j){
                if(b[j] == '1'){
                    byte |= 0x01 << 7-j;
                }
            }
            secuencia_bin.write(reinterpret_cast<char *>(&byte), sizeof(unsigned char));
        }
        secuencia_bin.close();
        
        /* Cifrar el fichero en claro */
        secuencia_bin.open("secuencia.bin", ios::in | ios::binary);
        en_claro.seekg(0, ios::beg);
        aux =  string(argv[2]);
        if(aux.substr(aux.size()-4,4) != ".cif"){
            aux += ".cif";
        }else{
            aux.erase(aux.size()-4,4);
        }
        
        cifrado.open(aux.c_str(), ios::out | ios::binary | ios::trunc);
        
        for(int i=0;i<numero_bits;i+=8){
            unsigned char byte1, byte2;
            secuencia_bin.read(reinterpret_cast<char *>(&byte1), sizeof(unsigned char));
            en_claro.read(reinterpret_cast<char *>(&byte2), sizeof(unsigned char));
            byte1 = byte1 ^ byte2; // XOR byte a byte
            cifrado.write(reinterpret_cast<char *>(&byte1), sizeof(unsigned char));
        }
        
        /* Cerrar archivos implicados */
        secuencia_bin.close();
        en_claro.close();
        cifrado.close();  
    }else{
        cout<<"ERROR: Imposible abrir el archivo "<<argv[2]<<endl;
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}
